// Copyright Epic Games, Inc. All Rights Reserved.

#include "LyraGameplayAbility_Interact.h"

#include "AbilitySystemComponent.h"
#include "Interaction/IInteractableTarget.h"
#include "Interaction/InteractionStatics.h"
#include "Interaction/Tasks/AbilityTask_GrantNearbyInteraction.h"
#include "NativeGameplayTags.h"
#include "Player/LyraPlayerController.h"
#include "UI/IndicatorSystem/IndicatorDescriptor.h"
#include "UI/IndicatorSystem/LyraIndicatorManagerComponent.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraGameplayAbility_Interact)

class UUserWidget;

// 定义交互激活的游戏标签
UE_DEFINE_GAMEPLAY_TAG_STATIC(TAG_Ability_Interaction_Activate, "Ability.Interaction.Activate");
// 定义交互持续时间的消息标签
UE_DEFINE_GAMEPLAY_TAG(TAG_INTERACTION_DURATION_MESSAGE, "Ability.Interaction.Duration.Message");

// 构造函数
ULyraGameplayAbility_Interact::ULyraGameplayAbility_Interact(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	ActivationPolicy = ELyraAbilityActivationPolicy::OnSpawn; // 设置Ability在生成时激活
	InstancingPolicy = EGameplayAbilityInstancingPolicy::InstancedPerActor; // 每个Actor实例化一个Ability
	NetExecutionPolicy = EGameplayAbilityNetExecutionPolicy::LocalPredicted; // 网络执行策略为本地预测
}

/**
 * 当Ability激活时调用
 */
void ULyraGameplayAbility_Interact::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
{
	Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData); // 调用父类实现

	UAbilitySystemComponent* AbilitySystem = GetAbilitySystemComponentFromActorInfo(); // 获取Actor的AbilitySystem组件
	if (AbilitySystem && AbilitySystem->GetOwnerRole() == ROLE_Authority) // 如果拥有Authority权限
	{
		// 创建并激活任务，用于授予附近交互器的能力
		UAbilityTask_GrantNearbyInteraction* Task = UAbilityTask_GrantNearbyInteraction::GrantAbilitiesForNearbyInteractors(this, InteractionScanRange, InteractionScanRate);
		Task->ReadyForActivation(); // 准备并激活任务
	}
}

/**
 * 更新交互选项和对应的指示器
 * @param InteractiveOptions 新的交互选项数组
 */
void ULyraGameplayAbility_Interact::UpdateInteractions(const TArray<FInteractionOption>& InteractiveOptions)
{
	if (ALyraPlayerController* PC = GetLyraPlayerControllerFromActorInfo()) // 获取玩家控制器
	{
		if (ULyraIndicatorManagerComponent* IndicatorManager = ULyraIndicatorManagerComponent::GetComponent(PC)) // 获取指示器管理器组件
		{
			for (UIndicatorDescriptor* Indicator : Indicators) // 遍历当前所有指示器
			{
				IndicatorManager->RemoveIndicator(Indicator); // 从管理器移除指示器
			}
			Indicators.Reset(); // 清空指示器数组

			for (const FInteractionOption& InteractionOption : InteractiveOptions) // 遍历新的交互选项
			{
				AActor* InteractableTargetActor = UInteractionStatics::GetActorFromInteractableTarget(InteractionOption.InteractableTarget); // 获取可交互目标对应的Actor

				// 确定使用的交互界面控件类，如果选项中的为空则使用默认的
				TSoftClassPtr<UUserWidget> InteractionWidgetClass = 
					InteractionOption.InteractionWidgetClass.IsNull() ? DefaultInteractionWidgetClass : InteractionOption.InteractionWidgetClass;

				UIndicatorDescriptor* Indicator = NewObject<UIndicatorDescriptor>(); // 创建新的指示器描述符
				Indicator->SetDataObject(InteractableTargetActor); // 设置数据对象为可交互Actor
				Indicator->SetSceneComponent(InteractableTargetActor->GetRootComponent()); // 设置场景组件为Actor的根组件
				Indicator->SetIndicatorClass(InteractionWidgetClass); // 设置指示器使用的控件类
				IndicatorManager->AddIndicator(Indicator); // 将指示器添加到管理器

				Indicators.Add(Indicator); // 将指示器添加到数组
			}
		}
		else
		{
			//TODO 这里可能需要一个明显的警告。为什么我们要在一个永远无法使用交互选项的PC上更新交互？
		}
	}

	CurrentOptions = InteractiveOptions; // 更新当前选项
}

/**
 * 触发当前首选（第一个）交互选项
 */
void ULyraGameplayAbility_Interact::TriggerInteraction()
{
	if (CurrentOptions.Num() == 0) // 如果没有可用的交互选项，直接返回
	{
		return;
	}

	UAbilitySystemComponent* AbilitySystem = GetAbilitySystemComponentFromActorInfo(); // 获取AbilitySystem组件
	if (AbilitySystem)
	{
		const FInteractionOption& InteractionOption = CurrentOptions[0]; // 获取第一个交互选项（通常是优先级最高的）

		AActor* Instigator = GetAvatarActorFromActorInfo(); // 获取发起交互的Avatar Actor
		AActor* InteractableTargetActor = UInteractionStatics::GetActorFromInteractableTarget(InteractionOption.InteractableTarget); // 获取可交互目标Actor

		// 准备游戏事件数据
		FGameplayEventData Payload;
		Payload.EventTag = TAG_Ability_Interaction_Activate; // 设置事件标签
		Payload.Instigator = Instigator; // 设置发起者
		Payload.Target = InteractableTargetActor; // 设置目标

		// 允许可交互目标自定义事件数据，例如，墙上的按钮可能希望指定一扇门Actor来执行Ability
		InteractionOption.InteractableTarget->CustomizeInteractionEventData(TAG_Ability_Interaction_Activate, Payload);

		// 从Payload中获取目标Actor，将其作为交互的'Avatar'，而源可交互目标Actor作为Owner Actor
		AActor* TargetActor = const_cast<AActor*>(ToRawPtr(Payload.Target));

		// 初始化用于交互的Actor信息
		FGameplayAbilityActorInfo ActorInfo;
		ActorInfo.InitFromActor(InteractableTargetActor, TargetActor, InteractionOption.TargetAbilitySystem);

		// 使用事件标签触发目标AbilitySystem上的Ability
		const bool bSuccess = InteractionOption.TargetAbilitySystem->TriggerAbilityFromGameplayEvent(
			InteractionOption.TargetInteractionAbilityHandle, // 目标交互Ability的句柄
			&ActorInfo, // Actor信息
			TAG_Ability_Interaction_Activate, // 事件标签
			&Payload, // 事件数据
			*InteractionOption.TargetAbilitySystem // 目标AbilitySystem组件
		);
	}
}